import torch
import os
import pandas as pd
# 创建目标文件夹和文件，用os
os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house.csv')
# 写入数据
with open(data_file, 'w') as f:
    f.write('Numrooms, Alley, Price\n') # 先写列名
    f.write('NA, Pave, 127500\n') # 按行写入每一个数据
    f.write('2, NAN, 106500\n') # 按行写入每一个数据
    f.write('4, NAN, 178200\n') # 按行写入每一个数据
    f.write('NA, NAN, 140000\n') # 按行写入每一个数据

# 使用pandas包的read_csv()函数来读取数据集
data = pd.read_csv(data_file)
print(data)

# 处理缺失值，先确定位置索引，用iloc[]
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2] #inputs为第一到第二列，outouts则为最后一列
inputs = inputs.fillna(inputs.mean()) #用同一列的均值替换缺失值
print(inputs)
# 对于inputs中的类别值或离散值，我们将"NaN"视为一个类别。
# 由于"巷子类型"（"Alley"）列只接受两 种类型的类别值"Pave"和"NaN"，pandas的get_dummies()函数可以自动将此列转换为两列"Alley_Pave"和"Alley_NAN"
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)

# 转换为张量格式
X = torch.tensor(inputs.to_numpy(dtype=float)) # 将数据先用numpy处理确定类型为float才可以转换为tensor
y = torch.tensor(outputs.to_numpy(dtype=float)) # 将数据先用numpy处理确定类型为float才可以转换为tensor
X, y

# 标量由只有一个元素的张量表示
x = torch.tensor(3)
y = torch.tensor(2)
x + y, x * y, x / y, x**y

# 一维张量即是向量
x = torch.arange(4)
x
x[3] # 同样用数组的方式索引访问
# len()函数访问向量的长度
len(x)

# 矩阵可以用二维张量表示
A = torch.arange(20).reshape(5, 4)
A
# 转置矩阵用A.T
A.T

# 张量的维数可以是任意的
X = torch.arange(24).reshape(2, 3, 4)
X
# 张量算法的基本性质：将两个相同形状的矩阵相加， 会在这两个矩阵上执行元素加法
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone() # 通过分配新内存，将A的一个副本分配给B
A, A+B
# ，两个矩阵的按元素乘法称为Hadamard积（Hadamard product）（数学符号⊙）
A * B
# 将张量乘以或加上一个标量不会改变张量的形状，其中张量的每个元素都将与标量相加或相乘
a = 2
X = torch.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape

# 降维（求和）
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
A.shape, A.sum()
test_Asum = A.sum()
test_Asum.shape # 使用sum（）函数之后变成一个标量了
# 也可以通过指定的轴进行求和降维
Asum_axis0 = A.sum(axis=0) # 所有行相加求和，列数不变，行降维只剩一行
Asum_axis0, Asum_axis0.shape
Asum_axis1 = A.sum(axis=1) # 所有列相加求和，行数不变，列降维只剩一列
Asum_axis1, Asum_axis1.shape
# 取平均值
A.mean() # 与sum()的作用类似，也降维
A.mean(axis=0) # 也可以通过指定轴进行取平均值

# 非降维求和，只需要在指定轴时加一个keepdims=True即可
sum_A = A.sum(axis=1, keepdim=True)
sum_A
# 使用广播机制检验是否保持维度不变
A / sum_A
# 沿某个轴计算A元素的累积总和，比如axis=0（按行计算），也可以调用cumsum函数
A.cumsum(axis=0)

# 向量的点积操作：torch.dot()
y = torch.ones(4, dtype=torch.float32)
x, y, torch.dot(x, y)
torch.sum(x*y) # 也可以通过使用元素乘积求和的方式实现点乘

# 矩阵的向量积:mv（）函数，矩阵向量积Ax是一个长度为m的列向量，其第i个元素是点 积a⊤i x，注意，A的列维数（沿轴1的长度）必须与x的维数（其长度）相同。
A.shape, x.shape, torch.mv(A, x)

# 矩阵乘法实现：torch.mm()函数
B = torch.ones(4, 3)
torch.mm(A, B)

# 线性代数中最有用的一些运算符是范数（norm）
# 计算L2范数，即变量的平方和再开平方
u = torch.tensor([3.0, 4.0])
torch.norm(u) # 这里数据类型要float，int不行
# 计算L1范数，即取绝对值再求和
torch.abs(u).sum()
# 一般的范数计算
torch.norm(torch.ones([4, 9]))
